package com.cxyd.modules.api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cxyd.common.constant.Constant;
import com.cxyd.common.constant.enums.api.ReceiveStatusEnum;
import com.cxyd.common.constant.enums.wms.*;
import com.cxyd.common.exception.RootException;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.DateUtils;
import com.cxyd.modules.api.dao.CallbackDao;
import com.cxyd.modules.api.dto.CallbackDTO;
import com.cxyd.modules.api.entity.CallbackEntity;
import com.cxyd.modules.api.service.CallbackService;
import com.cxyd.modules.wms.dao.*;
import com.cxyd.modules.wms.entity.*;
import com.cxyd.modules.wms.service.CommonService;
import com.cxyd.modules.wms.service.LocateService;
import com.cxyd.modules.wms.service.LogWorkService;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.cxyd.common.utils.DateUtils.DATE_TIME_PATTERN;

@Service
public class CallbackServiceImpl extends CrudServiceImpl<CallbackDao, CallbackEntity, CallbackDTO> implements CallbackService {
    private static final Logger logger = LoggerFactory.getLogger(CallbackServiceImpl.class);

    final TaskDao taskDao;
    final LocateDao locateDao;
    final StockDao stockDao;
    final CallbackDao callbackDao;
    final PostWcsDao postWcsDao;
    final LogWorkService logWorkService;
    final OrderDetailDao orderDetailDao;
    final CommonService commonService;
    final ContainerDao containerDao;
    final LocateService locateService;
    final StationDao stationDao;

    public CallbackServiceImpl(TaskDao taskDao, LocateDao locateDao, StockDao stockDao, CallbackDao callbackDao, PostWcsDao postWcsDao, LogWorkService logWorkService, OrderDetailDao orderDetailDao, CommonService commonService, ContainerDao containerDao, LocateService locateService, StationDao stationDao) {
        this.taskDao = taskDao;
        this.locateDao = locateDao;
        this.stockDao = stockDao;
        this.callbackDao = callbackDao;
        this.postWcsDao = postWcsDao;
        this.logWorkService = logWorkService;
        this.orderDetailDao = orderDetailDao;
        this.commonService = commonService;
        this.containerDao = containerDao;
        this.locateService = locateService;
        this.stationDao = stationDao;
    }


    @Override
    public QueryWrapper<CallbackEntity> getWrapper(Map<String, Object> params) {
        return null;
    }

    @Override
    public CallbackDTO getOneByPk(Map<String, Object> params) {
        String requestPk = (String) params.get("requestPk");
        final CallbackEntity entity = baseDao.getOneByPk(requestPk);
        return ConvertUtils.sourceToTarget(entity, CallbackDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void callBackProcess(CallbackDTO dto) {
        String requestPk = dto.getRequestPk();
        String contNo = dto.getContNo();
        String noticeType = dto.getNoticeType();
        String curPos = dto.getCurPos();
        String code = dto.getCode();
        String result = dto.getResult();
        Date startDate = new Date();
        //设备任务是否存在
        PostWcsEntity postWcsEntity = postWcsDao.selectOne(new QueryWrapper<PostWcsEntity>().eq("request_pk", requestPk));
        if (ObjectUtils.isEmpty(postWcsEntity) || PostWcsStEnum.ISSUED.getCode() != postWcsEntity.getTrkSt()) {
            throw new RootException("设备任务不存在或未下发！");
        }
        if (!contNo.equals(postWcsEntity.getContNo())) {
            throw new RootException("操作托盘与requestPk不对应！");
        }
        String toPos = postWcsEntity.getToPos();
        if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType) && !curPos.equals(toPos)) {
            String msg = "通知完成位置错误！ 完成位置toPos=" + toPos + "，当前位置curPos=" + curPos;
            throw new RootException(msg);
        }
        //查看执行任务
        QueryWrapper<TaskEntity> taskQuery = new QueryWrapper<TaskEntity>()
                .eq("cont_no", contNo)
                .eq("task_st", TaskStEnum.PROGRESS.getCode());
        List<TaskEntity> taskList = taskDao.selectList(taskQuery);
        if (CollectionUtils.isEmpty(taskList)) {
            throw new RootException("当前托盘没有执行中任务！");
        }
        LocateEntity locateEntity = locateDao.selectOne(new QueryWrapper<LocateEntity>().eq("locate_no", curPos));
        if (ObjectUtils.isEmpty(locateEntity)) {
            throw new RootException("当前位置不存在！");
        }
        Long userId = Constant.ClientCode.WCS.getId();
        String retCode = "0";
        String comment = "任务通知";
        String retMsg;
        String work = "api.callBackProcess";
        //日志记录
        LogWorkEntity insertLogWork = new LogWorkEntity();
        insertLogWork.setWorkName(comment);
        insertLogWork.setWorkProc(work);
        insertLogWork.setRelateNo(contNo);
        insertLogWork.setCreator(userId);
        insertLogWork.setCreateDate(startDate);
        //保存回调记录
        CallbackEntity insertCallBack = new CallbackEntity();
        insertCallBack.setRequestPk(requestPk);
        insertCallBack.setContNo(contNo);
        insertCallBack.setNoticeType(noticeType);
        insertCallBack.setCurPos(curPos);
        insertCallBack.setCode(code);
        insertCallBack.setResult(result);
        insertCallBack.setClientCode(dto.getClientCode());
        insertCallBack.setReqTime(DateUtils.format(new Date(), DATE_TIME_PATTERN));
        try {
            callbackDao.insert(insertCallBack);
        } catch (Exception e) {
            logger.info("保存回调记录失败", e);
            retCode = "1001";
            retMsg = e.getMessage();
            insertLogWork.setWorkCode(retCode);
            insertLogWork.setWorkMsg(retMsg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("保存回调记录失败！");
        }
        //修改设备任务
        PostWcsEntity updatePostWcs = new PostWcsEntity();
        if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)) {
            updatePostWcs.setTrkSt(PostWcsStEnum.COMPLETE.getCode());
        }
        updatePostWcs.setPostId(postWcsEntity.getPostId());
        updatePostWcs.setCurPos(curPos);
        updatePostWcs.setUpdater(userId);
        updatePostWcs.setUpdateDate(startDate);
        updatePostWcs.setComments(comment);
        try {
            postWcsDao.updateById(updatePostWcs);
        } catch (Exception e) {
            logger.info("修改设备任务失败", e);
            retCode = "1001";
            retMsg = e.getMessage();
            insertLogWork.setWorkCode(retCode);
            insertLogWork.setWorkMsg(retMsg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("修改设备任务失败！");
        }
        TaskEntity taskEntity = taskList.get(0);
        //修改任务
        TaskEntity updateTask = new TaskEntity();
        updateTask.setCurrentPosition(curPos);
        updateTask.setUpdater(userId);
        updateTask.setUpdateDate(startDate);
        updateTask.setComments(comment);
        //入库
        if (TaskTypeEnum.WAREHOUSE_ENTRY.getCode().equals(taskEntity.getTaskType())) {
            StockEntity updateStock = new StockEntity();
            updateStock.setCurPosition(curPos);
            updateStock.setPositionType(locateEntity.getLocateType());
            updateStock.setUpdater(userId);
            updateStock.setUpdateDate(startDate);
            updateStock.setComments(comment);
            if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)
                    && LocateTypeEnum.HW.getCode().equals(locateEntity.getLocateType())) {
                updateStock.setStockSt(StatusEnum.USABLE.getCode());
            }
            try {
                stockDao.update(updateStock, new QueryWrapper<StockEntity>().eq("cont_no", contNo));
            } catch (Exception e) {
                logger.info("修改库存失败", e);
                retCode = "1001";
                retMsg = e.getMessage();
                insertLogWork.setWorkCode(retCode);
                insertLogWork.setWorkMsg(retMsg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改库存失败！");
            }
            //修改任务
            if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)) {
                updateTask.setTaskSt(TaskStEnum.COMPLETE.getCode());
            }
        }
        //出库
        if (TaskTypeEnum.OUTBOUND.getCode().equals(taskEntity.getTaskType())) {
            //空托盘出库，删除空托盘库存
            if (TaskSubTypeEnum.EMPTY_PALLET_OUTBOUND.getCode().equals(taskEntity.getTaskSubType())) {
                if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)) {
                    updateTask.setTaskSt(TaskStEnum.COMPLETE.getCode());
                }
                try {
                    stockDao.delete(new QueryWrapper<StockEntity>().eq("cont_no", contNo));
                } catch (Exception e) {
                    logger.info("修改库存失败", e);
                    retCode = "1001";
                    retMsg = e.getMessage();
                    insertLogWork.setWorkCode(retCode);
                    insertLogWork.setWorkMsg(retMsg);
                    logWorkService.logWorkInsert(insertLogWork);
                    throw new RootException("修改库存失败！");
                }
            }
            //合料出库（需要生成合料回库的任务,等待合料放行或直接放行-新增2024年12月23日）
            if (TaskSubTypeEnum.STOCK_MERGE.getCode().equals(taskEntity.getTaskSubType())) {
                updateTask.setTaskSt(TaskStEnum.COMPLETE.getCode());
                //生成正常的入库任务
                TaskEntity insertTask = new TaskEntity();
                insertTask.setTaskType(TaskTypeEnum.WAREHOUSE_ENTRY.getCode());
                insertTask.setTaskSubType(TaskSubTypeEnum.WHOLE_PALLET_STORAGE.getCode());
                insertTask.setContNo(contNo);
                insertTask.setSpuNo(taskEntity.getSpuNo());
                insertTask.setSpuName(taskEntity.getSpuName());
                insertTask.setPlanQty(taskEntity.getPlanQty());
                insertTask.setActlQty(taskEntity.getActlQty());
                insertTask.setMtId(taskEntity.getMtId());
                insertTask.setMtNo(taskEntity.getMtNo());
                insertTask.setDetailId(taskEntity.getDetailId());
                insertTask.setStockId(taskEntity.getStockId());
                insertTask.setTaskSt(TaskStEnum.INITIAL.getCode());
                insertTask.setCreateDate(startDate);
                insertTask.setCreator(userId);
                insertTask.setComments(comment);
                //选择入库站台
                ContainerEntity containerEntity = containerDao.selectOne(new QueryWrapper<ContainerEntity>().eq("cont_no", contNo));
                String contType = containerEntity.getContType();
                List<StationEntity> stationEntities = stationDao.selectList(new QueryWrapper<StationEntity>()
                        .eq("dvc_no", contType)
                        .eq("station_type", PostWcsTypeEnum.IN.getCode())
                        .eq("station_st", StatusEnum.USABLE.getCode()));

                if (CollectionUtils.isEmpty(stationEntities)) {
                    throw new RootException("没有可用的入库站台！");
                } else {
                    //将库存当前位置更改为对应入库站台--更新时间2025年4月29日
                    stockDao.update(null, new UpdateWrapper<StockEntity>().eq("stock_id", taskEntity.getStockId())
                            .set("cur_position", stationEntities.get(0).getStationNo())
                            .set("updater", userId).set("update_date", startDate));
                }
                String stationNo = stationEntities.get(0).getStationNo();
                insertTask.setFromPosition(stationNo);
                insertTask.setCurrentPosition(stationNo);
                if (ContTypeEnum.HK.getCode().equals(contType)) {
                    //选择入库货位
                    try {
                        LocateEntity preAllocation = locateService.locatePreAllocation(containerEntity, contNo, containerEntity.getContType(), startDate, userId, comment);
                        insertTask.setToPosition(preAllocation.getLocateNo());
                    } catch (Exception e) {
                        logger.info("合料出库占用回库货位失败", e);
                        retCode = "1001";
                        retMsg = e.getMessage();
                        insertLogWork.setWorkCode(retCode);
                        insertLogWork.setWorkMsg(retMsg);
                        logWorkService.logWorkInsert(insertLogWork);
                        throw new RootException("合料出库占用回库货位失败！");
                    }
                }
                try {
                    taskDao.insert(insertTask);
                } catch (Exception e) {
                    logger.info("合料出库回库任务生成失败", e);
                    retCode = "1001";
                    retMsg = e.getMessage();
                    insertLogWork.setWorkCode(retCode);
                    insertLogWork.setWorkMsg(retMsg);
                    logWorkService.logWorkInsert(insertLogWork);
                    throw new RootException("合料出库回库任务生成失败！");
                }
            }
            //整托出库(只需要处理任务状态,无需扣减库存)
        }
//        盘点
        if (TaskTypeEnum.CHECK.getCode().equals(taskEntity.getTaskType())) {
//            盘点入库(更新任务状态完成,释放库存锁定)
            if (TaskSubTypeEnum.STOCK_RETURN.getCode().equals(taskEntity.getTaskSubType())) {
                StockEntity updateStock = new StockEntity();
                updateStock.setCurPosition(curPos);
                updateStock.setPositionType(locateEntity.getLocateType());
                updateStock.setUpdater(userId);
                updateStock.setUpdateDate(startDate);
                updateStock.setComments(comment);
                if (ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)
                        && LocateTypeEnum.HW.getCode().equals(locateEntity.getLocateType())) {
                    updateStock.setStockSt(StatusEnum.USABLE.getCode());
                }
                try {
                    stockDao.update(updateStock, new QueryWrapper<StockEntity>().eq("cont_no", contNo));
                } catch (Exception e) {
                    logger.info("盘点回库修改库存失败", e);
                    retCode = "1001";
                    retMsg = e.getMessage();
                    insertLogWork.setWorkCode(retCode);
                    insertLogWork.setWorkMsg(retMsg);
                    logWorkService.logWorkInsert(insertLogWork);
                    throw new RootException("盘点回库修改库存失败！");
                }
                updateTask.setTaskSt(TaskStEnum.COMPLETE.getCode());
            }
//            盘点出库
        }
        try {
            taskDao.update(updateTask, taskQuery);
        } catch (Exception e) {
            logger.info("修改任务失败", e);
            retCode = "1001";
            retMsg = e.getMessage();
            insertLogWork.setWorkCode(retCode);
            insertLogWork.setWorkMsg(retMsg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("修改任务失败！");
        }
        //库存位置统一修改
        stockDao.update(null, new UpdateWrapper<StockEntity>().eq("cont_no", contNo)
                .set("cur_position", curPos)
                .set("position_type", locateEntity.getLocateType())
                .set("updater", userId)
                .set("update_date", startDate)
                .set("comments", comment));

        //上架
        if (LocateTypeEnum.HW.getCode().equals(locateEntity.getLocateType())
                && ReceiveStatusEnum.COMPLETE.getCode().equals(noticeType)) {
            LocateEntity updateLocate = new LocateEntity();
            updateLocate.setLocateId(locateEntity.getLocateId());
            updateLocate.setContNo(contNo);
            updateLocate.setLocateSt(LocateStEnum.Apply.getCode());
            updateLocate.setUpdater(userId);
            updateLocate.setUpdateDate(startDate);
            updateLocate.setComments(comment);
            try {
                locateDao.updateById(updateLocate);
            } catch (Exception e) {
                logger.info("修改货位失败", e);
                retCode = "1001";
                retMsg = e.getMessage();
                insertLogWork.setWorkCode(retCode);
                insertLogWork.setWorkMsg(retMsg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改货位失败！");
            }
        }
        //下架
        String frmPos = postWcsEntity.getFrmPos();
        LocateEntity fromLocate = locateDao.selectOne(new QueryWrapper<LocateEntity>().eq("locate_no", frmPos));
        if (LocateTypeEnum.HW.getCode().equals(fromLocate.getLocateType()) && !frmPos.equals(curPos)) {
            LocateEntity updateLocate = new LocateEntity();
            updateLocate.setContNo(null);
            updateLocate.setLocateSt(LocateStEnum.FREE.getCode());
            updateLocate.setUpdater(userId);
            updateLocate.setUpdateDate(startDate);
            updateLocate.setComments(comment);
            try {
//                下架只看货位编号,符合直接释放即可-同时也要看是否被其他料箱占用
                locateDao.update(updateLocate, new UpdateWrapper<LocateEntity>()
                        .eq("locate_no", fromLocate.getLocateNo())
                        .eq("cont_no", contNo)
                        .ge("locate_st", LocateStEnum.FREE.getCode()));
            } catch (Exception e) {
                logger.info("修改货位失败", e);
                retCode = "1001";
                retMsg = e.getMessage();
                insertLogWork.setWorkCode(retCode);
                insertLogWork.setWorkMsg(retMsg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改货位失败！");
            }
        }
        retMsg = "接收到wcs任务执行通知!容器条码[" + contNo + "]当前位置[" + curPos + "]通知类型[" + noticeType + "]";
        insertLogWork.setWorkCode(retCode);
        insertLogWork.setWorkMsg(retMsg);
        logWorkService.logWorkInsert(insertLogWork);
    }
}
